package com.muc.socket;

import com.muc.view.MainView;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class NIOServer {


    private Selector selector;
//    private MainView mainView;
    ThreadPoolExecutor pool;//线程池用于处理一对多情况，同时更好管理资源


    public void initServer(int port) throws IOException {
        ServerSocketChannel serverChannel = ServerSocketChannel.open();//打开一个Channel
        serverChannel.configureBlocking(false);// 设置通道为非阻塞
        // 将该通道对应的ServerSocket绑定到port端口
        serverChannel.socket().bind(new InetSocketAddress(port));
        this.selector = Selector.open();//打开一个Selector
        //注册通道到Selector，并为该通道注册ACCEPT事件
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);

        pool = new ThreadPoolExecutor( 10,//核心线程数量
                100, //线程池的总数量
                60, //临时线程空闲时间
                TimeUnit.SECONDS, //临时线程空闲时间的单位
                new ArrayBlockingQueue<>(20),//阻塞队列
                Executors.defaultThreadFactory(),//创建线程的方式
                new ThreadPoolExecutor.AbortPolicy()//任务拒绝策略
        );
    }

    public void listen() throws IOException {
        System.out.println("Server is running...");
        while (true) {// 轮询访问selector
            selector.select(); //选择Channel
            Iterator ite = this.selector.selectedKeys().iterator();
            while (ite.hasNext()) {//遍历所有就绪Channel
                SelectionKey key = (SelectionKey) ite.next();
                ite.remove();// 删除已选的key,以防重复处理
                if (key.isAcceptable()) {//ServerSocketChannel接收到一个连接
                    //使用多线程代替
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                    //得到SocketChannel实例
                    SocketChannel socketChannel = serverSocketChannel.accept();

                    pool.submit(new MultiServerRunable(Selector.open(), socketChannel));
                }
            }
        }
    }
                /*if (key.isAcceptable()) {//ServerSocketChannel接收到一个连接
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel channel = server.accept();//接受请求
                    channel.configureBlocking(false);

                    //发送回复给客户
                    channel.write(ByteBuffer.wrap(new String("Send Ack back to client...").getBytes()));
                    //给Channel设置可读权限以继续接受请求
                    channel.register(this.selector, SelectionKey.OP_READ );

                } else if (key.isReadable()) {//Channel进入读模式
                    read(key);
                }
            }
        }
    }

    public void read(SelectionKey key) throws IOException{
        SocketChannel channel = (SocketChannel) key.channel();//返回一个SocketChannel
        ByteBuffer buffer = ByteBuffer.allocate(50);
        channel.read(buffer);
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("Server received msg："+msg);
        ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
        channel.write(outBuffer);//读取客户传递的数据
    }*/

    public static void main(String[] args) throws IOException {
        NIOServer server = new NIOServer();
        server.initServer(5555);
        server.listen();

        /*//1.打开服务端通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //2.让这个通道绑定一个端口
        serverSocketChannel.bind(new InetSocketAddress(666));
        //3.设置通道为非阻塞
        serverSocketChannel.configureBlocking(false);
        //4.打开一个选择器
        //Selector --- 选择器
        //        SelectionKey --- 绑定通道后返回那个令牌
        //      SelectableChannel --- 可以使用选择器的通道
        Selector selector = Selector.open();
        //5.绑定选择器和服务端通道
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
//        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT | SelectionKey.OP_READ | SelectionKey.OP_WRITE);
        while(true){
            System.out.println("11");
            //选择器会监视客户端通道的状态.
            //6.返回值就表示此时有多少个客户端来连接.
            int count = selector.select();
            System.out.println("222");
            if(count != 0){
                System.out.println("有客户端来连接了");
                //7.会遍历所有的服务端通道.看谁准备好了,谁准备好了,就让谁去连接.
                //获取所有服务端通道的令牌,并将它们都放到一个集合中,将集合返回.
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while(iterator.hasNext()){
                    //selectionKey 依次表示每一个服务端通道的令牌
                    SelectionKey selectionKey = iterator.next();
                    if(selectionKey.isAcceptable()){
                        //可以通过令牌来获取到了一个已经就绪的服务端通道
                        ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
                        //客户端的延伸通道
                        SocketChannel socketChannel = ssc.accept();
                        //将客户端延伸通道设置为非阻塞的
                        socketChannel.configureBlocking(false);
                        socketChannel.register(selector,SelectionKey.OP_READ);
                        //当客户端来连接的时候,所有的步骤已经全部执行完毕.
                    }else if(selectionKey.isReadable()){
                        //当前通道已经做好了读取的准备(延伸通道)
                        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                        ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);
                        //socketChannel.read(byteBuffer1);
                        int len;
                        while((len = socketChannel.read(byteBuffer1)) > 0){
                            byteBuffer1.flip();
                            System.out.println(new String(byteBuffer1.array(),0,len));
                            byteBuffer1.clear();
                        }
                        //给客户端的回写数据
                        socketChannel.write(ByteBuffer.wrap("哎哟喂好疼啊!!!".getBytes()));
                        socketChannel.close();
                    }
                    iterator.remove();
                }
            }
        }*/
    }
}